package org.liang.code.utils.pdf;


import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.lowagie.text.Document;
import com.lowagie.text.Font;
import com.lowagie.text.Image;
import com.lowagie.text.pdf.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PDFUtils {

    // 横向CJK字体
    public static final BaseFont CJKFont_H;
    // 纵向CJK字体
    public static final BaseFont CJKFont_V;

    // 静态代码块中实现逻辑 只注册一次
    static {
        try {
            CJKFont_H = BaseFont.createFont("font/NotoSerifCJKsc-VF.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            CJKFont_V = BaseFont.createFont("font/NotoSerifCJKsc-VF.ttf", BaseFont.IDENTITY_V, BaseFont.EMBEDDED);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 默认的标题字体
     * 横向写入，14号字体，加粗，黑色
     */
    public static final Font TITLE_FONT = new Font(CJKFont_H, 14, Font.BOLD, Color.BLACK);
    /**
     * 默认的正文字体
     * 横向写入，16号字体，加粗，黑色
     */
    public static final Font BODY_FONT = new Font(CJKFont_H, 12, Font.NORMAL, Color.BLACK);

    /**
     * 自定义字体
     * @param baseFont 基础字体
     * @param fontSize 字号
     * @param style 字体样式
     * @param color 字体颜色
     * @return Font
     */
    public static Font font(BaseFont baseFont, int fontSize, int style, Color color){
        return new Font(baseFont, fontSize, style, color);
    }

    /**
     * 创建条形码
     * @param writer writer
     * @param code 条形码内容
     * @return Image
     */
    public static Image barCode(PdfWriter writer, String code){
        Barcode qrCode = new Barcode128();
        qrCode.setCode(code);
        return qrCode.createImageWithBarcode(writer.getDirectContent(), Color.BLACK, Color.BLACK);
    }

    /**
     * 创建 PDF417 条形码
     * @param code 条形码内容
     * @return Image
     */
    public static Image barCode417(String code) throws IOException {
        BarcodePDF417 pdf417 = new BarcodePDF417();
        pdf417.setText(code);
        return Image.getInstance(pdf417.createAwtImage(Color.BLACK, Color.WHITE), null);
    }

    /**
     * 创建 DataMatrix 二维码
     * @param code 内容
     * @return Image
     */
    public static Image dataMatrix(String code) throws IOException {
        BarcodeDatamatrix datamatrix = new BarcodeDatamatrix();
        datamatrix.setHeight(16);
        datamatrix.setWidth(16);
        datamatrix.setBorder(2);
        datamatrix.setOptions(BarcodeDatamatrix.DM_AUTO);
        datamatrix.generate(code);
        return datamatrix.createImage();
    }

    /**
     * 创建二维码
     * @param code 二维码内容
     * @param length 二维码大小
     * @return Image
     */
    public Image qrCode(String code, int length) throws WriterException, IOException {

        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        BitMatrix encode = multiFormatWriter.encode(code, BarcodeFormat.QR_CODE, length, length);
        BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(encode);
        return Image.getInstance(bufferedImage, null);
    }

    /**
     * 创建带Logo的二维码
     * @param code 二维码内容
     * @param length 二维码大小
     * @param logoFile logo
     * @return Image
     */
    public Image qrCode(String code, int length, File logoFile) throws WriterException, IOException {

        Map<EncodeHintType, Object> hintMap = new HashMap<>();
        hintMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);  // 设置高容错级别
        // 生成二维码
        MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
        BitMatrix encode = multiFormatWriter.encode(code, BarcodeFormat.QR_CODE, length, length, hintMap);
        BufferedImage qrCodeImage = MatrixToImageWriter.toBufferedImage(encode,
                // 为什么要写这个? 因为会把二维码和图片全部渲染成黑白的
                new MatrixToImageConfig(MatrixToImageConfig.BLACK + 1, MatrixToImageConfig.WHITE)
        );

        // 读取logo图片
        BufferedImage logo = ImageIO.read(logoFile);
        // 获取二维码的宽高
        int qrWidth = qrCodeImage.getWidth();
        int qrHeight = qrCodeImage.getHeight();
        // 计算Logo的大小，设置为二维码的1/4大小
        int logoWidth = qrWidth / 4;
        int logoHeight = qrHeight / 4;
        // 在二维码中间绘制Logo
        Graphics2D g = qrCodeImage.createGraphics();
        int x = (qrWidth - logoWidth) / 2;
        int y = (qrHeight - logoHeight) / 2;
        // 绘制Logo
        g.drawImage(logo, x, y, logoWidth, logoHeight, null);
        g.setStroke(new BasicStroke(2)); // 画笔粗细
        g.setColor(Color.WHITE); // 边框颜色
        g.drawRect(x, y, qrWidth, qrHeight); // 矩形边框
        qrCodeImage.flush();
        g.dispose();
        return Image.getInstance(qrCodeImage, null);
    }

    /**
     * 读取表单域
     * @param reader PdfReader
     */
    public static void readFormFields (PdfReader reader) {
        // 获取AcroFields
        AcroFields form = reader.getAcroFields();

        // 获取所有表单域
        Map<String, AcroFields.Item> fields = form.getAllFields();

        /**
         * FIELD_TYPE_NONE = 0 未找到
         * FIELD_TYPE_PUSHBUTTON = 1 提交按钮
         * FIELD_TYPE_CHECKBOX = 2 复选框
         * FIELD_TYPE_RADIOBUTTON = 3 单选按钮
         * FIELD_TYPE_TEXT = 4 文本框
         * FIELD_TYPE_LIST = 5
         * FIELD_TYPE_COMBO = 6
         * FIELD_TYPE_SIGNATURE = 7 签名框
         */
        for (Map.Entry<String, AcroFields.Item> entry : fields.entrySet()) {
            String fieldName = entry.getKey();
            int fieldType = form.getFieldType(fieldName); // 获取表单域类型
            String fieldValue = form.getField(fieldName); // 获取表单域值

            System.out.println("表单域名称: " + fieldName +
                    ",\t\t 类型: " + fieldType +
                    ",\t\t 值: " + fieldValue);
        }
        reader.close();
    }

    /**
     * 填充表单域
     * @param reader PdfReader
     * @return byte[]
     */
    public static byte[] fillFormFields (PdfReader reader, Map<String, String> fieldValues) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        PdfStamper stamper = new PdfStamper(reader, byteArrayOutputStream);

        // 获取表单域
        AcroFields form = stamper.getAcroFields();

        // 这一行代表PDF是否嵌入字体 视情况
//        for (String string : form.getAllFields().keySet()) {
//            form.setFieldProperty(string, "textfont", CJKFont_H, null);
//        }

        // 填充表单域
        for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
            String fieldName = entry.getKey();
            String fieldValue = entry.getValue();
            form.setField(fieldName, fieldValue); // 设置表单域的值
        }

        // 设置表单域为只读
        stamper.setFormFlattening(true);

        stamper.close();
        reader.close();

        return byteArrayOutputStream.toByteArray();
    }

    /**
     * 合并PDF
     * @param outPath 输出新的PDF路径
     * @param pdfPath 被合并的PDFList
     */
    public void mergerPdf(String outPath, List<String> pdfPath) throws IOException {
        // 创建一个 Document 对象
        Document document = new Document();
        // 创建 PdfCopy 对象
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(outPath));
        document.open();
        for (String pdfFile : pdfPath) {
            PdfReader reader = new PdfReader(new FileInputStream(pdfFile));
            // 将每个文件的所有页面添加到新的 PDF 文件中
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {
                copy.addPage(copy.getImportedPage(reader, i));
            }
            reader.close();
        }
        document.close();
    }

    /**
     * 合并PDF
     * @param outPath 输出新的PDF路径
     * @param pdfPath 被合并的PDFList(InputStream)
     */
    public void mergerPdf2(String outPath, List<InputStream> pdfPath) throws IOException {
        // 创建一个 Document 对象
        Document document = new Document();
        // 创建 PdfCopy 对象
        PdfCopy copy = new PdfCopy(document, new FileOutputStream(outPath));
        document.open();
        for (InputStream pdfFile : pdfPath) {
            PdfReader reader = new PdfReader(pdfFile);
            // 将每个文件的所有页面添加到新的 PDF 文件中
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {
                copy.addPage(copy.getImportedPage(reader, i));
            }
            reader.close();
        }
        document.close();
    }

    /**
     * 拆分PDF
     * @param outPath 拆分后的位置
     * @param pdfPath 被拆的PDF
     * @return List
     */
    public List<String> splitPdf(String outPath, String pdfPath) throws IOException {
        PdfReader reader = new PdfReader(pdfPath);
        int totalPages = reader.getNumberOfPages();

        List<String> result = new ArrayList<String>();

        for (int i = 1; i <= totalPages; i++) {
            String outputFilePath = outPath + i + ".pdf";
            Document document = new Document();
            PdfCopy copy = new PdfCopy(document, new FileOutputStream(outputFilePath));
            document.open();
            copy.addPage(copy.getImportedPage(reader, i));
            document.close();
            result.add(outputFilePath);
        }
        reader.close();
        return result;
    }

    /**
     * 对PDF加密
     * @param reader PdfReader
     * @param os OutputStream
     * @param userPassword 用户密码
     * @param ownerPassword 管理员密码
     * @param permissions 用户权限 详见 PdfWriter的 ALLOW_PRINTING 等等
     */
    public void encryptPDF (PdfReader reader, OutputStream os, String userPassword, String ownerPassword, int permissions) throws IOException {
        PdfEncryptor.encrypt(reader, os, PdfWriter.STANDARD_ENCRYPTION_128, userPassword, ownerPassword, permissions);
    }





}
